package com.limh.gobang.view

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.os.Bundle
import android.os.Parcelable
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.limh.gobang.R
import com.limh.gobang.view.callback.ResultCallback

/**
 * @title： ${username}
 * @package： com.limh.gobang
 * @description：
 * @author： limh
 * @date： 2018/4/21
 * Copyright @2017 Corpration Name
 */
class GoBangView : View {
    //画笔
    private lateinit var paint: Paint
    //最大行数
    private val MAX_LINE = 10
    //棋盘每行行高
    private var lineHeight = 0.0
    //棋盘总宽度
    private var panelWidth = 0
    //白色棋子
    private lateinit var whitePiece: Bitmap
    //黑色棋子
    private lateinit var blackPiece: Bitmap
    //棋子占棋盘高度的3/4
    private val ratioPieceOfLineHeight = 3.0 / 4
    //白棋子先手，当前是白棋子
    var isWhite = true
    //棋子数
    var whiteArray = ArrayList<Point>()
    var blckArray = ArrayList<Point>()
    //游戏结束 false
    var isGameOver = true
    //白棋赢家 false
    var isWhiteWinner = false
    //棋局结果
    var resultCallback: ResultCallback? = null

    constructor (context: Context) : super(context) {
        init(context)
    }

    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
        init(context)
    }

    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        init(context)
    }

    private fun init(context: Context?) {
        //设置背景半透明红色
        paint = Paint()
        //棋盘线颜色半透明灰色
        paint.isAntiAlias = true
        paint.style = Paint.Style.FILL_AND_STROKE

        whitePiece = BitmapFactory.decodeResource(resources, R.drawable.ic_piece_w)
        blackPiece = BitmapFactory.decodeResource(resources, R.drawable.ic_piece_b)
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)

        var width = Math.min(widthSize, heightSize)
        if (widthMode == MeasureSpec.UNSPECIFIED) {
            width = heightSize + paddingEnd + paddingStart
        } else if (heightMode == MeasureSpec.UNSPECIFIED) {
            width = widthSize + paddingEnd + paddingStart
        }
        setMeasuredDimension(width, width)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        panelWidth = w
        lineHeight = panelWidth * 1.0 / MAX_LINE
        //重设棋子高宽
        val pieceWidth = lineHeight * ratioPieceOfLineHeight
        whitePiece = Bitmap.createScaledBitmap(whitePiece, pieceWidth.toInt(), pieceWidth.toInt(), false)
        blackPiece = Bitmap.createScaledBitmap(blackPiece, pieceWidth.toInt(), pieceWidth.toInt(), false)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        drawBoard(canvas)
        drawPieces(canvas)
        checkGameOver()
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        val action = event!!.action
        if (action == MotionEvent.ACTION_UP) {
            if (isGameOver) return false
            val x = event.x.toInt()
            val y = event.y.toInt()

            val point = getValiPoint(x, y)
            if (whiteArray.contains(point) || blckArray.contains(point)) {
                return false
            }
            if (isWhite) {
                whiteArray.add(point)
                if (null != resultCallback) {
                    resultCallback!!.onLocal(ResultCallback.WHITE, point)
                }
            } else {
                blckArray.add(point)
                if (null != resultCallback) {
                    resultCallback!!.onLocal(ResultCallback.BLACK, point)
                }
            }
            isWhite = !isWhite
            invalidate()
            return true
        }
        return true
    }

    fun start() {
        whiteArray.clear()
        blckArray.clear()
        isGameOver = false
        isWhiteWinner = false
        invalidate()
    }

    private val INSTANCE = "instance"
    private val INSTANCE_GAME_OVER = "instance_game_over"
    private val INSTANCE_WHITE_ARRAY = "instance_white_array"
    private val INSTANCE_BLACK_ARRAY = "instance_black_array"
    /**
     * 存储状态
     */
    override fun onSaveInstanceState(): Parcelable {
        val bundle = Bundle()
        bundle.putParcelable(INSTANCE, super.onSaveInstanceState())
        bundle.putBoolean(INSTANCE_GAME_OVER, isGameOver)
        bundle.putParcelableArrayList(INSTANCE_BLACK_ARRAY, blckArray)
        bundle.putParcelableArrayList(INSTANCE_WHITE_ARRAY, whiteArray)
        return bundle
    }

    /**
     * 恢复状态
     */
    override fun onRestoreInstanceState(state: Parcelable?) {
        if (state is Bundle) {
            isGameOver = state.getBoolean(INSTANCE_GAME_OVER)
            whiteArray = state.getParcelableArrayList(INSTANCE_WHITE_ARRAY)
            blckArray = state.getParcelableArrayList(INSTANCE_BLACK_ARRAY)
            super.onRestoreInstanceState(state.getParcelable(INSTANCE))
            return
        }
        super.onRestoreInstanceState(state)
    }

    /**
     * 获取点击的坐标值
     */
    private fun getValiPoint(x: Int, y: Int): Point {
        return Point((x / lineHeight).toInt(), (y / lineHeight).toInt())
    }

    //画棋盘
    private fun drawBoard(canvas: Canvas?) {
        val w = panelWidth
        val h = lineHeight
        for (i in 0..MAX_LINE) {
            val startX = (h / 2).toFloat()
            val endX = w - startX
            val y = ((0.5 + i) * h).toFloat()
            canvas!!.drawLine(startX, y, endX, y, paint)
            canvas.drawLine(y, startX, y, endX, paint)
        }
    }

    /**
     * 画棋子
     */
    private fun drawPieces(canvas: Canvas?) {
        paint.color = Color.BLACK
        for (item in whiteArray) {
            canvas!!.drawBitmap(whitePiece, ((item.x + (1 - ratioPieceOfLineHeight) / 2) * lineHeight).toFloat(),
                    ((item.y + (1 - ratioPieceOfLineHeight) / 2) * lineHeight).toFloat(), paint)
        }
        for (item in blckArray) {
            canvas!!.drawBitmap(blackPiece, ((item.x + (1 - ratioPieceOfLineHeight) / 2) * lineHeight).toFloat(),
                    ((item.y + (1 - ratioPieceOfLineHeight) / 2) * lineHeight).toFloat(), paint)
        }
    }

    /**
     * 检查游戏是否结束
     */
    private fun checkGameOver() {
        val whiteWin = checkWhiteWin(whiteArray)
        val blackWin = checkBlackWin(blckArray)
        if (blackWin || whiteWin) {
            isGameOver = true
            isWhiteWinner = whiteWin
            if (isWhiteWinner) {
                if (null != resultCallback)
                    resultCallback!!.isGameOver(ResultCallback.WHITE)
            } else {
                if (null != resultCallback)
                    resultCallback!!.isGameOver(ResultCallback.BLACK)
            }
        }
    }

    /**
     * 检查白棋是否赢
     */
    private fun checkWhiteWin(whiteArray: ArrayList<Point>): Boolean {
        for (item in whiteArray) {
            val x = item.x
            val y = item.y
            var win: Boolean = CheckInFive.checkHorizontal(x, y, whiteArray)
            if (win) return true
            win = CheckInFive.checkVertical(x, y, whiteArray)
            if (win) return true
            win = CheckInFive.checkLeftDiagonal(x, y, whiteArray)
            if (win) return true
            win = CheckInFive.checkRightDiagonal(x, y, whiteArray)
            if (win) return true
        }
        return false
    }

    /**
     * 检查黑棋是否赢
     */
    private fun checkBlackWin(blckArray: ArrayList<Point>): Boolean {
        for (item in blckArray) {
            val x = item.x
            val y = item.y
            var win: Boolean = CheckInFive.checkHorizontal(x, y, blckArray)
            if (win) return true
            win = CheckInFive.checkVertical(x, y, blckArray)
            if (win) return true
            win = CheckInFive.checkLeftDiagonal(x, y, blckArray)
            if (win) return true
            win = CheckInFive.checkRightDiagonal(x, y, blckArray)
            if (win) return true
        }
        return false
    }

}